package cn.yunyichina.provider.pay.service;

import cn.yunyichina.provider.framework.common.PKGenerator;
import cn.yunyichina.provider.framework.dubbo.service.CacheService;
import cn.yunyichina.provider.framework.page.PageInfo;
import cn.yunyichina.provider.framework.qiniu.QiniuService;
import cn.yunyichina.provider.framework.utils.ExcelUtil;
import cn.yunyichina.provider.iface.entity.common.Response;
import cn.yunyichina.provider.iface.entity.common.ResponseObject;
import cn.yunyichina.provider.pay.config.Config;
import cn.yunyichina.provider.pay.constant.ResponseEnum;
import cn.yunyichina.provider.pay.dao.PaymentJournalDao;
import cn.yunyichina.provider.pay.dao.PaymentSettingAppRelationDao;
import cn.yunyichina.provider.pay.dao.PaymentSettingDao;
import cn.yunyichina.provider.pay.dao.SettlementSettingDao;
import cn.yunyichina.provider.pay.entity.*;
import cn.yunyichina.provider.pay.model.vo.PaymentJournalVO;
import cn.yunyichina.provider.pay.service.impl.RedisCacheServiceImpl;
import cn.yunyichina.provider.pay.vo.FinanceExcel;
import cn.yunyichina.utils.commons.DateUtils;
import cn.yunyichina.utils.convert.JsonUtils;
import cn.yunyichina.utils.dozer.Dozer;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.apache.commons.collections.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.*;

@Service
public class PaymentServiceImpl {

    static Logger logger = LoggerFactory.getLogger(PaymentServiceImpl.class);

    @Autowired
    private PaymentJournalDao paymentJournalDao;

    @Autowired
    private PaymentSettingDao paymentSettingDao;

    @Autowired
    private SettlementSettingDao settlementSettingDao;

    @Autowired
    private RedisCacheServiceImpl redisCacheService;

    private PaymentSettingAppRelationDao paymentSettingAppRelationDao;

    @Resource
    private Properties yaml;

    public Response addPaymentJournal(String data, String sessionId) {
        Response response = new Response();
        PaymentJournal paymentJournal = JsonUtils.parseObject(data, PaymentJournal.class);
        paymentJournal.setId(PKGenerator.generateId());
        paymentJournal.setPaymentDealNo(CacheService.generateOrderNum(5, 1));
        paymentJournal.setCreatedTime(DateUtils.dateToString(new Date()));
        paymentJournalDao.insert(paymentJournal);
        return response;
    }

    /**
     * 根据id获取该组织下支付渠道
     * @interfaceName: yyt.pay.payment.setting.find
     * @return
     */
    public Response findPaymentSetting(String data) {
        Response response = new Response();
        PaymentSetting paymentSetting = JsonUtils.parseObject(data, PaymentSetting.class);
        List<PaymentSetting> select = paymentSettingDao.select(paymentSetting);
        if (select.size() > 0) {
            response.setResult(JsonUtils.toJsonString(select));
            response.setResultCodeAndMessage("0", "查询成功!");
        } else {
            response.setResult(null);
            response.setResultCodeAndMessage("10001", "查无结果");
        }

        return response;
    }

    public Response findPaymentJournal(String data, String sessionId) {
        Response response = new Response();
        PaymentJournal paymentJournal = JsonUtils.parseObject(data, PaymentJournal.class);
        List<PaymentJournal> pjs = paymentJournalDao.select(paymentJournal);
        if (pjs.size() > 0) {
            response.setResult(JsonUtils.toJsonString(pjs));
            response.setResultCodeAndMessage("0", "查询成功!");
        } else {
            response.setResult(null);
            response.setResultCodeAndMessage("10001", "查无结果");
        }
        return response;
    }

    public Response updatePaymentJournal(String data, String sessionId) {
        Response response = new Response();
        PaymentJournal paymentJournal = JsonUtils.parseObject(data, PaymentJournal.class);
        paymentJournalDao.update(paymentJournal);
        return response;
    }


    /**
     * 获取SettlementSetting配置
     *
     * @param datas
     * @return
     * @interfaceName:yyt.pay.payment.setting.by.settlement.setting.query
     */
    public ResponseObject queryPaymentSettingBySettlementSetting(String datas) {
        ResponseObject response = new ResponseObject();
        Map<String, String> dataMap = JSON.parseObject(datas, Map.class);
        String orgId = dataMap.get("org_id");
        SettlementSetting setting = new SettlementSetting();
        setting.setDevOrgId(orgId);

        List<SettlementSetting> settings = settlementSettingDao.select(setting);
        if (settings.size() > 0) {
            response.setResultObject(settings);
            response.setResultCodeAndMessage(response.getResultCode(), response.getResultMessage());
        } else {
            response.setResultObject(null);
            response.setResultCodeAndMessage("5002", "settleMentSetting数据查询失败!");
        }

        return response;
    }

    /**
     * 获取日期段内的交易流水记录
     *
     * @param data
     * @return
     */
    public ResponseObject listPaymentJournal(String data) {
        logger.info("病案复印对账列表原始入参 data ={}",data);
        PaymentJournal paymentJournal = JsonUtils.parseObject(data, PaymentJournal.class);
        PageInfo pageInfo = JsonUtils.parseObject(data, PageInfo.class);

        try {
            if (StringUtils.isEmpty(paymentJournal.getBeginPayTime()) ||
                    StringUtils.isEmpty(paymentJournal.getEndPayTime()) ||
                    StringUtils.isEmpty(pageInfo.getPageNum()) ||
                    StringUtils.isEmpty(pageInfo.getPageSize()) ||
                    pageInfo.getPageNum() < 0 || pageInfo.getPageSize() > 100)
                return new ResponseObject().buildResultCodeAndMessage(
                        ResponseEnum.Common.INVALID.getCode(), ResponseEnum.Common.INVALID.getMessage()
                );

            paymentJournal.setBeginPayTime(paymentJournal.getBeginPayTime() + " 00:00:00");
            paymentJournal.setEndPayTime(paymentJournal.getEndPayTime() + " 23:59:59");

            HashMap<String, Object> params = new HashMap<>();
            params.put("wheres", paymentJournal);
            params.put("pageInfo", pageInfo);

            List<Integer> statuses = new ArrayList<>();
            statuses.add(1);
            statuses.add(2);
            statuses.add(4);
            statuses.add(5);
            params.put("statuses", statuses);


            Map<String,PaymentJournal> journalsMap = new HashMap<>();
            PaymentJournalSum paymentJournalSum = paymentJournalDao.selectCountByListStatus(params);
            List<PaymentJournal> journals = paymentJournalDao.selectByListStatusForFuyin(params);
            if (!CollectionUtils.isEmpty(journals)){
                for (PaymentJournal pj: journals){
                    journalsMap.put(pj.getOrderNo()+"_"+pj.getPayStatus(),pj);
                }

                for (PaymentJournal pj: journals){
                    if (pj.getPayStatus() ==2){
                        PaymentJournal payPaymentJournal = journalsMap.get(pj.getOrderNo()+"_"+1);
                        PaymentJournal refundPaymentJournal = journalsMap.get(pj.getOrderNo()+"_"+2);
                        if (payPaymentJournal ==null){
                            PaymentJournal queryPaymentJournal = new PaymentJournal();
                            queryPaymentJournal.setOrderNo(pj.getOrderNo());
                            queryPaymentJournal.setPayStatus(new Short("1"));
                            List<PaymentJournal> paymentJournalList = paymentJournalDao.select(queryPaymentJournal);
                            payPaymentJournal = paymentJournalList.get(0);
                        }
                        Integer realIncome = payPaymentJournal.getTotalAmount() - refundPaymentJournal.getTotalAmount();
                        pj.setRealIncome(realIncome);
                    }
                }
            }

            Map<String, Object> result = new HashMap<>();
            if (!CollectionUtils.isEmpty(journals)) {
                List<PaymentJournalVO> vos = new ArrayList<>();
                for (PaymentJournal journal : journals) {
                    vos.add(Dozer.convert(journal, PaymentJournalVO.class));
                }
                result.put("list", vos);
            }

            result.put("currentPayAmount", paymentJournalSum.getCurrentPayAmount());
            result.put("currentRefundAmount", paymentJournalSum.getCurrentRefundAmount());
            result.put("currentIncomeAmount", paymentJournalSum.getCurrentIncomeAmount());

            result.put("page_num", pageInfo.getPageNum());
            result.put("page_size", pageInfo.getPageSize());
            result.put("count", paymentJournalSum.getCnt());

            return new ResponseObject().buildResultObject(result);
        } catch (Exception e) {
            logger.error("PaymentServiceImpl.listPaymentJournal.Exception", e);
            return new ResponseObject().buildResultCodeAndMessage(
                    ResponseEnum.Common.FAILURE.getCode(), ResponseEnum.Common.FAILURE.getMessage()
            );
        }
    }

    /**
     * 支付配置列表查询 yyt.pay.payment.setting.list
     *
     * @param data
     * @return
     */
    public Response listPaymentSetting(String data) {
        Response response = new Response();
        PaymentSetting setting = JsonUtils.parseObject(data, PaymentSetting.class);

        Map<String, String> maps = JsonUtils.parseObject(data, Map.class);
        String pageNum = maps.get("page_num");
        String pageSize = maps.get("page_size");

        Map<String, Object> result = new HashMap<>();
        List<PaymentSetting> list = null;
        PageInfo pageInfo = new PageInfo();
        //查询，如需分页则计算分页信息
        if (org.apache.commons.lang.StringUtils.isNotBlank(pageNum) && org.apache.commons.lang.StringUtils.isNotBlank(pageSize)) {
            long count = paymentSettingDao.selectCount(setting);
            pageInfo.setTotal(count);
            pageInfo.setPageNum(Integer.valueOf(pageNum));
            pageInfo.setPageSize(Integer.valueOf(pageSize));
            pageInfo.setPages((pageInfo.getTotal().intValue() + pageInfo.getPageSize() - 1) / pageInfo.getPageSize());
            list = paymentSettingDao.select(setting, pageInfo);
        } else {
            list = paymentSettingDao.select(setting);
        }
        result.put("list", list);
        result.put("page_info", pageInfo);

        response.setResultCodeAndMessageAndResult("0", "查询成功", JsonUtils.toJsonString(result));
        return response;
    }

    /**
     * 支付配置列表保存 yyt.pay.payment.setting.save
     *
     * @param data
     * @return
     */
    public Response savePaymentSetting(String data, String sessionId) {
        Response response = new Response();
        PaymentSetting setting = JsonUtils.parseObject(data, PaymentSetting.class);
        if (org.apache.commons.lang.StringUtils.isBlank(setting.getId())) {
            setting.setId(PKGenerator.generateId());
            setting.setCreatedTime(DateUtils.dateToString(new Date()));
            paymentSettingDao.insert(setting);
        } else {
            setting.setUpdateTime(DateUtils.dateToString(new Date()));
            paymentSettingDao.update(setting);
        }

        return response;
    }

    /**
     * 查找应用或医院下支付配置列表
     * yyt.pay.payment.setting.by.appcode.and.orgcode.list
     *
     * @param data
     * @param sessionId
     * @return
     */
    public Response listPaymentSettingByAppcodeAndOrgcode(String data, String sessionId) {
        logger.info("PaymentSettingServiceImpl.listPaymentSettingByAppcodeAndOrgcode,data=" + data);
        Response response = new Response();
        PaymentSettingAppRelation psarWheres = JsonUtils.parseObject(data, PaymentSettingAppRelation.class);
        List<PaymentSetting> list = paymentSettingDao.listPaymentSettingByAppcodeAndOrgcode(psarWheres);
        if (com.alibaba.dubbo.common.utils.CollectionUtils.isEmpty(list)) {
//            throw new PaySettingNotFoundException("查询条件platformOrgAppCode:" + platformOrgAppCode + ",orgCode:" + payOrgCode + "在表[PAY_PAYMENT_SETTING_APP_RELATION]中没有记录!");
        }
        response.setResult(JsonUtils.toJsonString(list));
        response.setResultCodeAndMessage("0", "查询成功");
        return response;
    }

    /**
     * 保存应用下支付配置
     *
     * @param data
     * @param sessionId
     * @return
     */
    public Response savePaymentSettingAppRelation(String data, String sessionId) {
        logger.info("PaymentSettingServiceImpl.savePaymentSettingAppRelation,data=" + data);
        Response response = new Response();

        PaymentSettingAppRelation appRelation = JsonUtils.parseObject(data, PaymentSettingAppRelation.class);
        appRelation.setId(PKGenerator.generateId());
        paymentSettingAppRelationDao.insert(appRelation);
        response.setResult(JsonUtils.toJsonString(appRelation));
        response.setResultCodeAndMessage("0", "保存成功");
        return response;
    }

    /**
     * 日期段内的交易流水记录 导出excel
     * yyt.pay.payment.journal.excel.download
     *
     * @param data
     * @return
     */
    public ResponseObject downloadPaymentJournalExcel(String data) {
        logger.info("病案复印对账导出excel原始入参 data ={}",data);
        PaymentJournal paymentJournal = JsonUtils.parseObject(data, PaymentJournal.class);

        try {
            if (StringUtils.isEmpty(paymentJournal.getBeginPayTime()) ||
                    StringUtils.isEmpty(paymentJournal.getEndPayTime()))
                return new ResponseObject().buildResultCodeAndMessage(
                        ResponseEnum.Common.INVALID.getCode(), ResponseEnum.Common.INVALID.getMessage()
                );

            paymentJournal.setBeginPayTime(paymentJournal.getBeginPayTime() + " 00:00:00");
            paymentJournal.setEndPayTime(paymentJournal.getEndPayTime() + " 23:59:59");

            HashMap<String, Object> params = new HashMap<>();
            params.put("wheres", paymentJournal);

            List<Integer> statuses = new ArrayList<>();
            statuses.add(1);
            statuses.add(2);
            statuses.add(4);
            statuses.add(5);
            params.put("statuses", statuses);

            List<PaymentJournal> journals = paymentJournalDao.selectByListStatusForFuyin(params);
            Map<String,PaymentJournal> journalsMap = new HashMap<>();

            if (!CollectionUtils.isEmpty(journals)){
                for (PaymentJournal pj: journals){
                    journalsMap.put(pj.getOrderNo()+"_"+pj.getPayStatus(),pj);
                }
                for (PaymentJournal pj: journals){
                    if (pj.getPayStatus() ==2){
                        PaymentJournal payPaymentJournal = journalsMap.get(pj.getOrderNo()+"_"+1);
                        PaymentJournal refundPaymentJournal = journalsMap.get(pj.getOrderNo()+"_"+2);
                        if (payPaymentJournal ==null){
                            PaymentJournal queryPaymentJournal = new PaymentJournal();
                            queryPaymentJournal.setOrderNo(pj.getOrderNo());
                            queryPaymentJournal.setPayStatus(new Short("1"));
                            List<PaymentJournal> paymentJournalList = paymentJournalDao.select(queryPaymentJournal);
                            payPaymentJournal = paymentJournalList.get(0);
                        }
                        Integer realIncome = payPaymentJournal.getTotalAmount() - refundPaymentJournal.getTotalAmount();
                        pj.setRealIncome(realIncome);
                    }
                }
            }

            Map<String, Object> result = new HashMap<>();
            if (!CollectionUtils.isEmpty(journals)) {
                List<Map<String, Object>> vos = new ArrayList<>();
                for (PaymentJournal journal : journals) {
//                    vos.add(Dozer.convert(journal, PaymentJournalVO.class));
                    Map<String, Object> map = new HashedMap();
                    map.put("order_no", journal.getOrderNo());
                    String payTime = journal.getPayTime();
                    if (payTime != null && payTime.length() > 20) {
                        payTime = payTime.substring(0, 19);
                    }
                    map.put("pay_time", payTime);
                    float payAmount = journal.getPayAmount();
                    if (journal.getPayStatus() == 2) {
                        map.put("pay_amount", 0 - payAmount / 100f);
                        map.put("pay_status", "退款");
                    } else {
                        map.put("pay_amount", payAmount / 100f);
                        map.put("pay_status", "支付");
                    }
                    map.put("pat_name",journal.getPatName());
                    map.put("apply_user_name",journal.getApplyUserName());
                    if(journal.getRealIncome() != null){
                        map.put("real_income",journal.getRealIncome() / 100f);
                    }
                    vos.add(map);
                }
                result.put("list", vos);

                JSONArray ja = JSONArray.parseArray(JsonUtils.toJsonString(vos));
                Map<String, String> headMap = new LinkedHashMap<String, String>();
                headMap.put("order_no", "订单号");
                headMap.put("pay_amount", "金额");
                headMap.put("pay_time", "交易时间");
                headMap.put("pay_status", "状态");
                headMap.put("pat_name", "患者");
                headMap.put("apply_user_name", "申请人");
                headMap.put("real_income", "实际收入");
                String title = "对账报表";

                String savePath = yaml.getProperty(Config.CONFIG_PAY_ALIPAY_CHECK_ACCOUNT_PATH);
                String fileName = paymentJournal.getOrgCode().trim() + "_对账流水.xlsx";
                String filePath = URLDecoder.decode(savePath + fileName, "UTF-8");

                OutputStream outXlsx = new FileOutputStream(filePath);
                Date d2 = new Date();
                ExcelUtil.exportExcelX(title, headMap, ja, null, 0, outXlsx);
                logger.info("共" + vos.size() + "条数据,执行" + (new Date().getTime() - d2.getTime()) + "ms");
                outXlsx.close();

                com.qiniu.http.Response upres = QiniuService.upload(filePath, fileName,
                        Config.QINIU_BUCKET_FOR_FINANCEEXCEL);
                if (upres.isOK() || upres.statusCode == 614) {
                    logger.info("upload Excel file success!");
                    String bucketURL = yaml.getProperty(Config.QINIU_FINANCE_EXCEL_DOWNLOAD_URL);
                    String path = yaml.getProperty(Config.CONFIG_PAY_ALIPAY_CHECK_ACCOUNT_PATH);

                    String url = QiniuService.download(fileName, path, bucketURL);
                    if (org.apache.commons.lang.StringUtils.isBlank(url)) {
                        return new ResponseObject().buildResultCodeAndMessage("2", "Get FinanceBill Excel Url for online is null !");
                    }

                    return new ResponseObject().buildResultCodeAndMessageAndResult(Response.SUCCESS_CODE, Response.SUCCESS_MESSAGE,
                            new FinanceExcel(url));
                } else {
                    logger.info("financeExcel_qiniu_upload_fail!!");
                    return new ResponseObject().buildResultCodeAndMessage("2", "失败");
                }
            }

            return new ResponseObject().buildResultObject(result);
        } catch (Exception e) {
            logger.error("PaymentServiceImpl.listPaymentJournal.Exception", e);
            return new ResponseObject().buildResultCodeAndMessage(
                    ResponseEnum.Common.FAILURE.getCode(), ResponseEnum.Common.FAILURE.getMessage()
            );
        }
    }

    public ResponseObject reloadPaymentSettingCache(String params) {
        logger.info("PaymentSettingServiceImpl.reloadPaymentSettingCache.params -> {}", params);
        ResponseObject response = new ResponseObject();

        try {
            Map map = JsonUtils.parseObject(params, Map.class);
            assert map != null;
            String appCode = (String) map.get("app_code");
            String orgCode = (String) map.get("org_code");
            String payCode = (String) map.get("pay_code");
            if (StringUtils.isEmpty(appCode) || StringUtils.isEmpty(payCode)) {
                response.setResultCodeAndMessage(
                        ResponseEnum.Common.INVALID.getCode(),
                        ResponseEnum.Common.INVALID.getMessage()
                );

                return response;
            }

            boolean flag = redisCacheService.reloadPaymentSettingCache(appCode, orgCode, payCode);
            if (!flag) {
                response.setResultCodeAndMessage(
                        ResponseEnum.Common.FAILURE.getCode(),
                        ResponseEnum.Common.FAILURE.getMessage()
                );
            }
        } catch (Exception e) {
            logger.error("PaymentSettingServiceImpl.reloadPaymentSettingCache.Exception", e);
            response.setResultCodeAndMessageAndResult(
                    ResponseEnum.Common.FAILURE.getCode(),
                    ResponseEnum.Common.FAILURE.getMessage(),
                    e.getMessage()
            );
        }

        return response;
    }

}
